package net.csdn.business.framework.audit.aop;

import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.annotation.AuditStatusCheck;
import net.csdn.business.common.domain.ResponseResult;
import net.csdn.business.common.enums.AuditEnum;
import net.csdn.business.common.enums.ResultCodeEnum;
import net.csdn.business.common.exception.BusinessException;
import net.csdn.business.common.utils.ExceptionUtil;
import net.csdn.business.common.utils.JsonUtil;
import net.csdn.business.common.utils.UserInfoParser;
import net.csdn.business.framework.audit.config.AuditStrategyConfig;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author wanghang
 * @version 1.0
 * @date 2022/7/7 19:58
 */
@Aspect
@Component
@Slf4j
@SuppressWarnings({"unchecked"})
@ConditionalOnProperty(name = "audit.aspect.enable", havingValue = "true")
public class AuditStatusCheckAspect {

    private final static String RESULT = "result";

    private final AuditStrategyConfig auditStrategyConfig;

    public AuditStatusCheckAspect(AuditStrategyConfig auditStrategyConfig) {
        this.auditStrategyConfig = auditStrategyConfig;
    }

    @Pointcut("@annotation(net.csdn.business.common.annotation.AuditStatusCheck)")
    public void pointCut() {

    }

    /**
     * 根据审核状态校验详情可见性
     *
     * @param joinPoint 切入点
     * @param result    result
     */
    @AfterReturning(value = "pointCut()", returning = RESULT, argNames = "joinPoint,result")
    public void doAfterReturningAdvice(JoinPoint joinPoint, Object result) {
        if (!auditStrategyConfig.getAuditEnable()) {
            return;
        }
        try {
            checkDetail(joinPoint, result);
        } catch (BusinessException e) {
            log.error("==== 根据审核状态校验详情可见性,发生异常：{}", e.getMessage());
            if (e.getResultCodeName().equalsIgnoreCase(ResultCodeEnum.CONTENT_CHECK_ERROR.name())) {
                log.error("==== 根据审核状态校验详情可见性, 资源审核中，暂不可见！");
                ExceptionUtil.throwBizException(ResultCodeEnum.RESOURCE_NOT_EXIST, ResultCodeEnum.CONTENT_CHECK_ERROR.getMsg());
            }
            throw e;
        }
    }

    private void checkDetail(JoinPoint joinPoint, Object result) {
        if (ObjectUtils.isEmpty(result)) {
            return;
        }

        Object respData;
        if (result instanceof ResponseResult) {
            if (((ResponseResult<?>) result).getCode() != ResultCodeEnum.OK.getCode()) {
                return;
            }
            respData = ((ResponseResult<?>) result).getData();
            if (ObjectUtils.isEmpty(respData)) {
                return;
            }
        } else {
            respData = result;
        }
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        AuditStatusCheck auditStatusCheck = method.getAnnotation(AuditStatusCheck.class);
        AuditEnum.DataTypeEnum resourceType = auditStatusCheck.resourceType();
        String statusFieldName = auditStatusCheck.statusFieldName();
        String userIdFieldName = auditStatusCheck.userIdFieldName();
        log.info("==== 根据审核状态校验详情可见性,userIdFieldName={},statusFieldName={},resourceType={}", userIdFieldName, statusFieldName, resourceType);

        // 执行过滤
        if (resourceType == AuditEnum.DataTypeEnum.JSON_OBJECT) {
            JSONObject data = JsonUtil.toJsonObject(respData);
            // 当前登录用户ID
            String crrUserId = UserInfoParser.getUserId();
            // 审核状态
            Integer auditStatus = data.getInteger(statusFieldName);
            // 返回字段中的用户ID
            String userId = data.getOrDefault(userIdFieldName, "").toString();

            log.info("==== 根据审核状态校验详情可见性,crrUserId={},auditStatus={},userId={}", crrUserId, auditStatus, userId);

            // 查看自己的详情数据，不做限制
            if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(crrUserId) && userId.equals(crrUserId)) {
                return;
            }
            // 审核通过
            if (AuditEnum.AuditStatusEnum.PASS.getCode().equals(auditStatus)) {
                return;
            }
            // 审核失败
            if (AuditEnum.AuditStatusEnum.FAIL.getCode().equals(auditStatus)) {
                throw new BusinessException(ResultCodeEnum.CONTENT_CHECK_ERROR);
            }
            // 分时段执行过滤（仅支持详情）
            Boolean visible = auditStrategyConfig.resVisible(auditStatus);
            if (null == auditStatus || !visible) {
                throw new BusinessException(ResultCodeEnum.CONTENT_CHECK_ERROR);
            }
        }
    }
}